package iit.projects.etaxi.view.bean;

import iit.projects.etaxi.model.dto.DriverSCDO;
import iit.projects.etaxi.model.dto.ReservationSCDO;
import iit.projects.etaxi.model.entity.Customer;
import iit.projects.etaxi.model.entity.Driver;
import iit.projects.etaxi.model.entity.Reservation;
import iit.projects.etaxi.model.service.DriverService;
import iit.projects.etaxi.model.service.ReservationService;
import iit.projects.etaxi.model.service.ServiceLocator;
import iit.projects.etaxi.util.Constants;
import iit.projects.etaxi.util.JSFUtils;

import java.util.ArrayList;
import java.util.List;

import javax.faces.component.UIInput;
import javax.faces.event.ActionEvent;
import javax.faces.event.ValueChangeEvent;
import javax.faces.model.SelectItem;

import ca.odell.glazedlists.FilterList;
import ca.odell.glazedlists.GlazedLists;
import ca.odell.glazedlists.TextFilterator;
import ca.odell.glazedlists.matchers.TextMatcherEditor;

import com.icesoft.faces.component.ext.HtmlInputText;
import com.icesoft.faces.component.selectinputdate.SelectInputDate;
import com.icesoft.faces.component.selectinputtext.SelectInputText;

public class ReservationDetailsBackingBean {
	
	private ReservationSCDO reservationSCDO;
	private List<Reservation> reservations;
	private String selectedReservationCode;
	private List<Driver> drivers;
	private List<SelectItem> driverCodeSelItms;
	private List<SelectItem> driverNameSelItms;
	private boolean assignMode;
	private String driverCode;
	private String driverName;
	private String panelHeader;
	
	private HtmlInputText compResCode;
	private SelectInputDate compStartDate;
	private SelectInputDate compEndDate;
	private SelectInputText compDriverCode;
	private SelectInputText compDriverName;
	private SelectItem selectedDriver;
	private TextMatcherEditor<SelectItem> driverCodeMatcherEditor;
	private TextMatcherEditor<SelectItem> driverNameMatcherEditor;
	
	private ServiceLocator serviceLocator;
	private ReservationService reservationService;
	private DriverService driverService;
	
	@javax.annotation.PostConstruct
	public void init(){
		reservationSCDO = new ReservationSCDO();
		reservationService = serviceLocator.getReservationService();
		driverService = serviceLocator.getDriverService();
		panelHeader = JSFUtils.getResourcesProperty("reservation.details.panel.header");
		
		Boolean loggedAsOperator = (Boolean)JSFUtils.getFromSession(Constants.LOGGED_IN_AS_OPERATOR);
		if(loggedAsOperator != null && loggedAsOperator){
			populateDriverDetails();
		}
	}
	
	public void searchReservations(ActionEvent event){
		
		Boolean loggedAsCustomer = (Boolean)JSFUtils.getFromSession(Constants.LOGGED_IN_AS_CUSTOMER);
		if(loggedAsCustomer != null && loggedAsCustomer){
			Customer customer = (Customer)JSFUtils.getFromSession(Constants.CUSTOMER);
			reservationSCDO.setCustomer(customer);
			reservations = reservationService.searchReservations(reservationSCDO);
		}
		else{
			reservationSCDO.setCustomer(null);
			reservations = reservationService.searchReservations(reservationSCDO);
		}
		if(this.reservations == null || this.reservations.isEmpty()){
			JSFUtils.addFacesInfoMessage("data.notfound");
			return;
		}
	}
	
	public void clear(ActionEvent event){
		reservationSCDO = new ReservationSCDO();
		
		compResCode.resetValue();
		compStartDate.resetValue();
		compEndDate.resetValue();
	}
	
	public void cancelReservation(ActionEvent event){
		Reservation reservation = findReservationByCode(selectedReservationCode);
		if(reservation != null){
			if(!reservation.getStatus().equals(Constants.ReservationStatus.NEW)){
				JSFUtils.addFacesErrorMessage("reservation.cannot.becanceled");
				return;
			}
			try{
				reservation.setStatus(Constants.ReservationStatus.CANCELED);
				reservationService.updateReservation(reservation);
				JSFUtils.addFacesInfoMessage("reservation.cancel.successfull");
			}catch(Throwable e){
				return;
			}
			//return;
		}
		else{
			JSFUtils.addFacesErrorMessage("reservation.not.selected");
			return;
		}
	}
	
	public void confirmCancel(ActionEvent event){
		ConfirmationPopupBackingBean confirmBean = 
			(ConfirmationPopupBackingBean)JSFUtils.getManagedBeanValue("confirmationPopup");
		confirmBean.setMessage(JSFUtils.getResourcesProperty("cancel.reservation.confirmation"));
		confirmBean.setBackingBeanAlias("reservationDetailsBean");
		confirmBean.setMethodName("cancelReservation");
		confirmBean.setShowPopup(true);
		
		selectedReservationCode = ((String)JSFUtils.getRequestParameter("code"));
	}
	
	private Reservation findReservationByCode(String reservationCode){
		for(Reservation reservation : reservations){
			if(reservation.getCode().equals(reservationCode)){
				return reservation;
			}
		}
		return null;
	}
	
	public void changeToAssignMode(ActionEvent event){
		selectedReservationCode = ((String)JSFUtils.getRequestParameter("code"));
		panelHeader = JSFUtils.getResourcesProperty("reservation.requestdriver.panel.header", 
				new Object[]{selectedReservationCode});
		assignMode = true;
	}
	
	private void populateDriverDetails(){
		//Find All Drivers
		drivers = driverService.findDrivers(new DriverSCDO());
		
		if(drivers != null && !drivers.isEmpty()){
			TextFilterator<SelectItem> driverCodeSelectItemFilterator = new TextFilterator<SelectItem>() {
				@Override
				public void getFilterStrings(List<String> baseList,
						SelectItem element) {
					baseList.add(element.getLabel());
				}
			};
			TextFilterator<SelectItem> driverNameNameSelectItemFilterator = new TextFilterator<SelectItem>() {
				@Override
				public void getFilterStrings(List<String> baseList,
						SelectItem element) {
					baseList.add(element.getLabel());
				}
			};
			
			driverCodeMatcherEditor = new TextMatcherEditor<SelectItem>(driverCodeSelectItemFilterator);
			driverNameMatcherEditor = new TextMatcherEditor<SelectItem>(driverNameNameSelectItemFilterator);
			
			populateDriverSelectItems();
			
			driverCodeSelItms = new FilterList<SelectItem>(GlazedLists.eventList(driverCodeSelItms), driverCodeMatcherEditor);
			driverNameSelItms = new FilterList<SelectItem>(GlazedLists.eventList(driverNameSelItms), driverNameMatcherEditor);
		}
	}
	
	private void populateDriverSelectItems(){
		driverCodeSelItms = new ArrayList<SelectItem>();
		driverNameSelItms = new ArrayList<SelectItem>();
		
		for(Driver driver : drivers){
			driverCodeSelItms.add(new SelectItem(driver, driver.getCode()));
			driverNameSelItms.add(new SelectItem(driver, driver.getName()));
		}
	}
	
	public void requestDriver(ActionEvent event){
		
		if(driverCode == null || driverCode.isEmpty()){
			JSFUtils.addFacesErrorMessage(compDriverCode, UIInput.REQUIRED_MESSAGE_ID);
			return;
		}
		if(driverName == null || driverName.isEmpty()){
			JSFUtils.addFacesErrorMessage(compDriverName, UIInput.REQUIRED_MESSAGE_ID);
			return;
		}
		
		if(selectedDriver == null){
			selectedDriver = compDriverCode.getSelectedItem();
		}
		if(selectedDriver == null){
			JSFUtils.addFacesErrorMessage(compDriverCode, "driver.code.invalid");
			return;
		}
		else if(!driverName.equals(((Driver)selectedDriver.getValue()).getName())){
			JSFUtils.addFacesErrorMessage(compDriverName, "driver.name.invalid");
			return;
		}
		
		Reservation reservation = findReservationByCode(selectedReservationCode);
		Driver driver = (Driver)selectedDriver.getValue();
		
		Reservation updated = reservationService.requestDriverForReservation(reservation, driver);
		this.reservations.set(reservations.indexOf(reservation), updated);
		
		JSFUtils.addFacesInfoMessage("reservation.request.successfull", new Object[]{driverName, selectedReservationCode});
		panelHeader = JSFUtils.getResourcesProperty("reservation.details.panel.header");
		assignMode = false;
		
		driverCode = null;
		driverName = null;
		compDriverCode.resetValue();
		compDriverName.resetValue();
	}
	
	public void cancelRequest(ActionEvent event){
		panelHeader = JSFUtils.getResourcesProperty("reservation.details.panel.header");
		assignMode = false;
	}
	
	public void valueChangeDriverCode(ValueChangeEvent event){
		if (event.getComponent() instanceof SelectInputText) {
			SelectInputText selectInputText = (SelectInputText) event.getComponent();
			String value = (String) event.getNewValue();

			driverCodeMatcherEditor.setMode(Constants.TEXT_MATCHER_EDITOR_MODE);
			driverCodeMatcherEditor.setFilterText((value == null) ? new String[] {} : new String[] { value });

			selectedDriver = selectInputText.getSelectedItem();
			if (selectedDriver != null) {
				Driver driver = (Driver) selectedDriver.getValue();
				driverName = driver.getName();
				compDriverName.resetValue();
			}
		}
	}
	
	public void valueChangeDriverName(ValueChangeEvent event){
		if (event.getComponent() instanceof SelectInputText) {
			SelectInputText selectInputText = (SelectInputText) event.getComponent();
			String value = (String) event.getNewValue();

			driverNameMatcherEditor.setMode(Constants.TEXT_MATCHER_EDITOR_MODE);
			driverNameMatcherEditor.setFilterText((value == null) ? new String[] {} : new String[] { value });

			selectedDriver = selectInputText.getSelectedItem();
			if (selectedDriver != null) {
				Driver driver = (Driver) selectedDriver.getValue();
				driverCode = driver.getCode();
				compDriverCode.resetValue();
			}
		}
	}

	public List<Reservation> getReservations() {
		return reservations;
	}

	public void setReservations(List<Reservation> reservations) {
		this.reservations = reservations;
	}

	public HtmlInputText getCompResCode() {
		return compResCode;
	}

	public void setCompResCode(HtmlInputText compResCode) {
		this.compResCode = compResCode;
	}

	public void setServiceLocator(ServiceLocator serviceLocator) {
		this.serviceLocator = serviceLocator;
	}

	public ReservationSCDO getReservationSCDO() {
		return reservationSCDO;
	}

	public void setReservationSCDO(ReservationSCDO reservationSCDO) {
		this.reservationSCDO = reservationSCDO;
	}

	public SelectInputDate getCompStartDate() {
		return compStartDate;
	}

	public void setCompStartDate(SelectInputDate compStartDate) {
		this.compStartDate = compStartDate;
	}

	public SelectInputDate getCompEndDate() {
		return compEndDate;
	}

	public void setCompEndDate(SelectInputDate compEndDate) {
		this.compEndDate = compEndDate;
	}

	public List<SelectItem> getDriverCodeSelItms() {
		return driverCodeSelItms;
	}

	public void setDriverCodeSelItms(List<SelectItem> driverCodeSelItms) {
		this.driverCodeSelItms = driverCodeSelItms;
	}

	public List<SelectItem> getDriverNameSelItms() {
		return driverNameSelItms;
	}

	public void setDriverNameSelItms(List<SelectItem> driverNameSelItms) {
		this.driverNameSelItms = driverNameSelItms;
	}

	public boolean isAssignMode() {
		return assignMode;
	}

	public void setAssignMode(boolean assignMode) {
		this.assignMode = assignMode;
	}

	public SelectInputText getCompDriverCode() {
		return compDriverCode;
	}

	public void setCompDriverCode(SelectInputText compDriverCode) {
		this.compDriverCode = compDriverCode;
	}

	public SelectInputText getCompDriverName() {
		return compDriverName;
	}

	public void setCompDriverName(SelectInputText compDriverName) {
		this.compDriverName = compDriverName;
	}

	public String getDriverCode() {
		return driverCode;
	}

	public void setDriverCode(String driverCode) {
		this.driverCode = driverCode;
	}

	public String getDriverName() {
		return driverName;
	}

	public void setDriverName(String driverName) {
		this.driverName = driverName;
	}

	public String getPanelHeader() {
		return panelHeader;
	}

	public void setPanelHeader(String panelHeader) {
		this.panelHeader = panelHeader;
	}
}
